import multiprocessing
import os
import socket
import threading

import util

# res = None
# for item in method_pool:
#     if item[1] == req_url and item[0].__contains__(req_type):
#         res = item[2]({'name': True})
#         break
#
# res and print(res)
import time


class Request:
    def __init__(self, suffix):
        self.req_type = 'GET'
        self.req_path = '/'
        self.req_http = 'HTTP/1.1'
        self.static_suffix = suffix

    def setOneLine(self, *args):
        if args:
            return
        print(args)
        self.req_type, self.req_path, self.req_http = args

    def is_static_URL(self):
        bo = False
        for i in self.static_suffix:
            if self.req_path.endswith(i):
                bo = True
                break
        return bo


class Response:
    def __init__(self):
        self.RESP_200_HEADER = 'HTTP/1.1 200 OK\n\r'
        self.RESP_404_HEADER = 'HTTP/1.1 404 not found\n\r'
        self.RESP_DATE = f'Date: {time.ctime()}\n\r'
        self.RESP_SERVER = 'Server: Python Web Server\n\r'
        self.RESP_CONTENT_LENGTH = 'Content-Length: 0\n\r'
        self.RES_ACCEPT_RANGES = 'Accept-Ranges: bytes\n\r'
        self.RESP_CONTENT_TYPE = 'Content-Type: text/html; charset=utf-8\n\r'
        self.RESP_BODY = ''


def is_static(req_path):
    if req_path.endswith('.html'):
        return True, 'Content-Type: text/html; charset=utf-8 \n\r'
    elif req_path.endswith('.css'):
        return True, 'Content-Type: text/css; charset=utf-8 \n\r'
    elif req_path.endswith('.js'):
        return True, 'Content-Type: text/javascript; charset=utf-8 \n\r'
    elif req_path.endswith('.png') or req_path.endswith('.apng'):
        return True, 'Content-Type: image/* \n\r'
    elif req_path.endswith('.jpg'):
        return True, 'Content-Type: image/jpg \n\r'
    elif req_path.endswith('.webp'):
        return True, 'Content-Type: image/webp \n\r'
    elif req_path.endswith('.gif'):
        return True, 'Content-Type: image/gif \n\r'
    elif req_path.endswith('.svg'):
        return True, 'Content-Type: image/svg+xml \n\r'
    elif req_path.endswith('.ttf'):
        return True, 'Content-Type: application/octet-stream; charset=utf-8 \n\r'
    elif req_path.endswith('.woff2'):
        return True, 'Content-Type: application/octet-stream; charset=utf-8 \n\r'
    else:
        return False, 'Content-Type: text/json charset=utf-8 \n\r'


class Server:
    def __init__(self, pool, config):
        util.print_banner()
        self.control_pool = [(k, {k: v}) for con in pool for k, v in con.__dict__.items() if
                             not k.startswith('__')]
        print()
        with os.popen("py -V") as cmd:
            util.log(f" the python env is {cmd.read()}", "server.server", os.getpid())
        util.log(" control_pool init success", "server.server", os.getpid())
        self.method_pool = [item[1].get(item[0])() for item in self.control_pool]
        util.log(" method_pool init success", "server.server", os.getpid())
        self.port = int(config.get('port'))
        util.log(f" [ http-port: {self.port} ]", "server.server", os.getpid())
        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        util.log(f" server_socket create success.", "server.server", os.getpid())
        self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        util.log(f" server_socket setsockopt success", "server.server", os.getpid())
        self.server_socket.bind(('', self.port))
        util.log(f" server_socket bind port success.", "server.server", os.getpid())
        self.server_socket.listen(config.get('listen'))
        util.log(f" {config.get('listen')} clients can be connected at the same time", "server.server", os.getpid())
        self.new_socket = None
        self.request = Request(config.get('static_suffix'))
        self.root_path = os.path.dirname(os.path.abspath(__file__)).replace("server", '') + config.get('path').get(
            'root')
        util.log(f" server context path /{config.get('path').get('root')}", "server.server", os.getpid())
        self.not_found = config.get('path').get('404')

    def run(self):
        util.log(f" App Running at http://localhost:{self.port}", 'server.server', os.getpid())
        while True:
            new_socket, new_adr = self.server_socket.accept()
            p = threading.Thread(target=self.handle_req, args=(new_socket,))
            p.start()
            p.join()
            new_socket.close()
        self.server_socket.close()

    def handle_req(self, req):
        request = req.recv(1024).decode('utf-8', errors='ignore')
        if not request:
            return
        req_lines = request.splitlines()
        # for i, line in enumerate(req_lines):
        #     print(i, line)
        resp = Response()
        # print(self.request.req_path)
        req_method, req_path, req_http = req_lines[0].split(' ')
        req_path = req_path.split('?')[0]
        is_s, content_type = is_static(req_path)
        if is_s:
            try:
                with open(f"{self.root_path}{req_path}", 'rb') as f:
                    content = f.read()
                # content = file.read()
                # resp.RESP_CONTENT_LENGTH = f'Content-Length: {len(content)}\n\r'
                resp.RESP_CONTENT_TYPE = content_type
                req.send(
                    f"{resp.RESP_200_HEADER}{resp.RESP_CONTENT_TYPE}\n\r".encode(
                        'utf-8'))
                req.send(content)
            except FileNotFoundError:
                resp.RESP_CONTENT_TYPE = 'Content-Type: text/html; charset=utf-8\n\r'
                with open(f"{self.root_path}{self.not_found}", 'rb') as f:
                    content = f.read()
                # resp.RESP_CONTENT_LENGTH = f'Content-Length: {len(content)}\n\r'
                req.send(
                    f'{resp.RESP_404_HEADER}{resp.RESP_CONTENT_TYPE}\n\r'.encode(
                        "utf-8"))
                print(content)
                req.send(content)
            finally:
                req.close()
        else:
            resp.RESP_CONTENT_TYPE = "Content-Type: text/json; charset=utf-8\r\n"
            req.send(f"{resp.RESP_200_HEADER}{resp.RESP_CONTENT_TYPE}\r\n".encode('utf-8'))
            resp.RESP_BODY = '{"code": 200, "data": [1,2,3,45,6]}'
            req.send(resp.RESP_BODY.encode('utf-8'))
        req.close()
